home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MonitorDoubler / Source / GDeviceUtils.cp next >
Encoding:
Text File  |  2000-06-23  |  14.2 KB  |  577 lines

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    GDeviceUtils.cp
  4. #
  5. #    by Eric Traut
  6. #
  7. ------------------------------------------------------------------------------*/
  8.  
  9. #include "GDeviceUtils.h"
  10.  
  11. #include <Memory.h>
  12. #include <LowMem.h>
  13. #include <Displays.h>
  14. #include <Traps.h>
  15. #include <Resources.h>
  16. #include <Sound.h>
  17.  
  18.  
  19. /*---------------------------------------------------------------
  20.     GraphicSurface
  21. ---------------------------------------------------------------*/
  22.  
  23. GraphicSurface::GraphicSurface()
  24. {
  25.     // Nothing to do
  26.     mPixelData = NULL;
  27. }
  28.         
  29.  
  30. /*---------------------------------------------------------------
  31.     ExtractRealDeviceInfo
  32. ---------------------------------------------------------------*/
  33.  
  34. void
  35. GraphicSurface::ExtractRealDeviceInfo(
  36.     GDHandle            inGDevice)
  37. {
  38.     PixMapHandle        pixMap;
  39.     
  40.     pixMap = inGDevice[0]->gdPMap;
  41.     
  42.     mRowBytes = pixMap[0]->rowBytes & 0x3FFF;
  43.     mPixelData = (UInt8 *)pixMap[0]->baseAddr;
  44.     mBitDepth = pixMap[0]->pixelSize;
  45.     mHeight = pixMap[0]->bounds.bottom - pixMap[0]->bounds.top;
  46.     mWidth = pixMap[0]->bounds.right - pixMap[0]->bounds.left;
  47. }
  48.  
  49.  
  50. /*---------------------------------------------------------------
  51.     CapturedGDevice
  52. ---------------------------------------------------------------*/
  53.  
  54. CapturedGDevice::CapturedGDevice()
  55. {
  56.     mGDHandle = NULL;
  57.     mDeviceCaptured = false;
  58.  
  59.     mVirtualDevice = NULL;
  60.  
  61.     mBlendEffect = NULL;
  62. }
  63.         
  64.  
  65. /*---------------------------------------------------------------
  66.     ~CapturedGDevice
  67. ---------------------------------------------------------------*/
  68.  
  69. CapturedGDevice::~CapturedGDevice()
  70. {
  71.     if (mDeviceCaptured)
  72.         UncaptureDevice();
  73. }
  74.         
  75.  
  76. /*---------------------------------------------------------------
  77.     CaptureDevice
  78. ---------------------------------------------------------------*/
  79.  
  80. void
  81. CapturedGDevice::CaptureDevice(
  82.     GDHandle            inGDevice,
  83.     VirtualGDevice *    inVDevice)
  84. {
  85.     if (mDeviceCaptured)
  86.         UncaptureDevice();
  87.  
  88.     mGDHandle = inGDevice;
  89.     
  90.     OSErr err = ::DMGetDisplayIDByGDevice(inGDevice, &mDisplayID, false);
  91.     if (err != noErr)
  92.         DebugStr("\pCouldn't get DisplayID");
  93.     
  94.     mCapturedSurface.ExtractRealDeviceInfo(mGDHandle);
  95.  
  96.     // For now, we only support 16-bit mode.
  97.     if (mCapturedSurface.GetBitDepth() != 16)
  98.     {
  99.         // fix me - report an error
  100.         SysBeep(0);
  101.     }
  102.     else
  103.     {
  104.         mVirtualDevice = inVDevice;
  105.  
  106.         ::HideCursor();
  107.  
  108.         Handle        tempHandle = NULL;
  109.  
  110.         // Tell the virtual monitor to initialize itself.
  111.         inVDevice->Initialize(*this, tempHandle);
  112.  
  113.         ::DMSetMainDisplay(inVDevice->GetGDHandle(), tempHandle);
  114.  
  115.         // We need to recompute the GDHandle from the display ID
  116.         // because they may have been rearranged.
  117.         RecomputeGDHandle();
  118.         inVDevice->RecomputeGDHandle();
  119.  
  120.         // Now get rid of the rounded area in the corners
  121.         SetDeviceAttribute(inVDevice->GetGDHandle(), roundedDevice, false);
  122.  
  123.         // Force a complete redraw now.
  124.         UInt32 depth = 16;
  125.         ::DMSetDisplayMode(inVDevice->GetGDHandle(), 100, &depth, 0, NULL);
  126.  
  127.         ::ShowCursor();
  128.         
  129.         mDeviceCaptured = true;
  130.     }
  131. }
  132.  
  133.  
  134. /*---------------------------------------------------------------
  135.     UncaptureDevice
  136. ---------------------------------------------------------------*/
  137.  
  138. void
  139. CapturedGDevice::UncaptureDevice()
  140. {
  141.     if (mDeviceCaptured)
  142.     {
  143.         RecomputeGDHandle();
  144.         OSErr err = ::DMSetMainDisplay(mGDHandle, NULL);
  145.         if (err != noErr)
  146.             DebugStr("\p Error SetMainDisplay");
  147.         RecomputeGDHandle();
  148.  
  149.         // Tell each of the virtual monitors to 
  150.         // uninitialize itself.
  151.         if (mVirtualDevice != NULL)
  152.             mVirtualDevice->Uninitialize();
  153.  
  154.         mDeviceCaptured = false;
  155.     }
  156. }
  157.         
  158.  
  159. /*---------------------------------------------------------------
  160.     SetPixelBase
  161. ---------------------------------------------------------------*/
  162.  
  163. void
  164. CapturedGDevice::SetPixelBase(
  165.     UInt8 *                inPixelBase)
  166. {
  167.     PixMapHandle        pixMap;
  168.     
  169.     RecomputeGDHandle();
  170.     if (mGDHandle != NULL)
  171.     {
  172.         pixMap = mGDHandle[0]->gdPMap;
  173.         pixMap[0]->baseAddr = (Ptr)inPixelBase;
  174.     }
  175. }
  176.  
  177.  
  178. /*---------------------------------------------------------------
  179.     UpdateCapturedScreen
  180. ---------------------------------------------------------------*/
  181.  
  182. void
  183. CapturedGDevice::UpdateCapturedScreen()
  184. {
  185.     if (mBlendEffect != NULL)
  186.         mBlendEffect->RenderVirtualDevice(mCapturedSurface, mVirtualDevice);
  187. }
  188.  
  189.  
  190. /*---------------------------------------------------------------
  191.     RecomputeGDHandle
  192. ---------------------------------------------------------------*/
  193.  
  194. void
  195. CapturedGDevice::RecomputeGDHandle()
  196. {
  197.     OSErr        err;
  198.  
  199.     err = ::DMGetGDeviceByDisplayID(mDisplayID, &mGDHandle, false);
  200.     
  201.     if (err != noErr)
  202.     {
  203.         DebugStr("\pFailedToFindDevice");
  204.         mGDHandle = NULL;
  205.     }
  206. }
  207.  
  208.  
  209. /*---------------------------------------------------------------
  210.     SetGraphicBlendEffect
  211. ---------------------------------------------------------------*/
  212.  
  213. void
  214. CapturedGDevice::SetGraphicBlendEffect(
  215.     GraphicBlendEffect *    inBlendEffect)
  216. {
  217.     if (mBlendEffect != NULL)
  218.     {
  219.         GraphicBlendEffect *        tempEffect = mBlendEffect;
  220.         
  221.         // Set it to NULL first so time manager
  222.         // task doesn't call the effect after it's 
  223.         // deallocated.
  224.         mBlendEffect = NULL;
  225.         delete tempEffect;
  226.     }
  227.  
  228.     // We need to wipe the dest screen to black
  229.     ClearCapturedScreen();
  230.     
  231.     mBlendEffect = inBlendEffect;
  232. }
  233.  
  234.  
  235. /*---------------------------------------------------------------
  236.     ClearCapturedScreen
  237. ---------------------------------------------------------------*/
  238.  
  239. void
  240. CapturedGDevice::ClearCapturedScreen()
  241. {
  242.     // The simple blend effect simply involves
  243.     // copying the pixels from the first virtual
  244.     // device to the destination surface.
  245.     UInt32                 totalRows = mCapturedSurface.GetHeight();
  246.     UInt32                 totalCols = mCapturedSurface.GetWidth();
  247.     UInt8 *             destPtr;
  248.     
  249.     for (UInt32 row = 0; row < totalRows; row++)
  250.     {
  251.         destPtr = mCapturedSurface.GetPixelDataPtr() + mCapturedSurface.GetRowBytes() * row;
  252.         
  253.         for (UInt32 col = 0; col < totalCols; col++)
  254.         {
  255.             *(UInt16 *)destPtr = 0;
  256.             destPtr += 2;
  257.         }
  258.     }
  259. }
  260.  
  261.  
  262. /*---------------------------------------------------------------
  263.     VirtualGDevice
  264. ---------------------------------------------------------------*/
  265.  
  266. VirtualGDevice::VirtualGDevice()
  267. {
  268.     mDeviceBacking = NULL;
  269.     mGDHandle = NULL;
  270.     mAddedToDeviceList = false;
  271. }
  272.  
  273.  
  274. /*---------------------------------------------------------------
  275.     ~VirtualGDevice
  276. ---------------------------------------------------------------*/
  277.  
  278. VirtualGDevice::~VirtualGDevice()
  279. {
  280.     Uninitialize();
  281. }
  282.  
  283.  
  284. /*---------------------------------------------------------------
  285.     Initialize
  286. ---------------------------------------------------------------*/
  287.  
  288. Boolean
  289. VirtualGDevice::Initialize(
  290.     CapturedGDevice &        inRealGDevice,
  291.     Handle                    inDMConfigHandle)
  292. {
  293.     // Allocate backing memory for the virtual device
  294.     Ptr backingPtr;
  295.     backingPtr = ::NewPtrClear(inRealGDevice.GetGraphicSurface().GetBackingSize() * 4);
  296.     
  297.     if (backingPtr == NULL)
  298.         return false;
  299.     
  300.     mDeviceBacking = backingPtr;
  301.     
  302.     // Allocate a new GDevice if this isn't the primary
  303.     // virtual device.
  304.     
  305.     // fix me - what is the first parameter?
  306.     mGDHandle = ::NewGDevice(0, -1);
  307.     if (mGDHandle == NULL)
  308.         return false;
  309.     ::HLock((Handle)mGDHandle);
  310.  
  311.     Handle itableHandle;
  312.     
  313.     itableHandle = ::NewHandle(0);
  314.     if (itableHandle == NULL)
  315.         return false;
  316.     
  317.     // Make a default inverse table
  318.     ::MakeITable(NULL, (ITabHandle)itableHandle, 4);
  319.     
  320.     mGDHandle[0]->gdRefNum = 0;
  321.     mGDHandle[0]->gdID = 128;
  322.     mGDHandle[0]->gdType = 2;
  323.     mGDHandle[0]->gdITable = (ITabHandle)itableHandle;
  324.     mGDHandle[0]->gdFlags = (1L << gdDevType) |            // Color device
  325.                             (1L << noDriver) |            // No driver
  326.                             (1L << screenDevice) |        // It's a screen device (not printer)
  327.                             (1L << screenActive) |        // It's active
  328.                             (1L << burstDevice);
  329.     mGDHandle[0]->gdMode = 129;
  330.  
  331.     // Set up the device rectangle
  332.     mGDHandle[0]->gdRect.left = 0;
  333.     mGDHandle[0]->gdRect.top = 0;
  334.     mGDHandle[0]->gdRect.right = inRealGDevice.GetGraphicSurface().GetWidth() * 2;
  335.     mGDHandle[0]->gdRect.bottom = inRealGDevice.GetGraphicSurface().GetHeight() * 2;
  336.  
  337.     // Now, set up the pix map for the gdevice
  338.     PixMapHandle        realPixMap = inRealGDevice.GetPixMapHandle();
  339.     PixMapHandle        virtPixMap = mGDHandle[0]->gdPMap;
  340.  
  341.     // Copy the pix map info 
  342.     virtPixMap[0]->baseAddr = mDeviceBacking;
  343.     virtPixMap[0]->rowBytes = ((realPixMap[0]->rowBytes & 0x3FFF) * 2) | (realPixMap[0]->rowBytes & 0xC000);
  344.     virtPixMap[0]->bounds = realPixMap[0]->bounds;
  345.     virtPixMap[0]->bounds.bottom *= 2;
  346.     virtPixMap[0]->bounds.right *= 2;
  347.     virtPixMap[0]->pmVersion = realPixMap[0]->pmVersion;
  348.     virtPixMap[0]->packType = realPixMap[0]->packType;
  349.     virtPixMap[0]->packSize = realPixMap[0]->packSize;
  350.     virtPixMap[0]->hRes = realPixMap[0]->hRes;
  351.     virtPixMap[0]->vRes = realPixMap[0]->vRes;
  352.     virtPixMap[0]->pixelType = realPixMap[0]->pixelType;
  353.     virtPixMap[0]->pixelSize = realPixMap[0]->pixelSize;
  354.     virtPixMap[0]->cmpCount = realPixMap[0]->cmpCount;
  355.     virtPixMap[0]->cmpSize = realPixMap[0]->cmpSize;
  356.     virtPixMap[0]->planeBytes = realPixMap[0]->planeBytes;
  357.     virtPixMap[0]->pmReserved = realPixMap[0]->pmReserved;
  358.  
  359.     if (virtPixMap[0]->pmTable != NULL)
  360.     {
  361.         virtPixMap[0]->pmTable[0]->ctSeed = 0xF;
  362.         virtPixMap[0]->pmTable[0]->ctFlags = 0x8000;
  363.     }
  364.     
  365.     ::DMAddDisplay(        mGDHandle, 
  366.                         mGDHandle[0]->gdRefNum, 
  367.                         mGDHandle[0]->gdMode, 
  368.                         0, 
  369.                         0, 
  370.                         NULL, 
  371.                         inDMConfigHandle);
  372.     ::DMEnableDisplay(mGDHandle, inDMConfigHandle);
  373.  
  374.     OSErr err = ::DMGetDisplayIDByGDevice(mGDHandle, &mDisplayID, false);
  375.     if (err != noErr)
  376.         DebugStr("\pCouldn't get DisplayID");
  377.  
  378.     mAddedToDeviceList = true;
  379.  
  380.     mVirtualSurface.ExtractRealDeviceInfo(mGDHandle);
  381.  
  382.     return true;
  383. }
  384.  
  385.  
  386. /*---------------------------------------------------------------
  387.     Uninitialize
  388. ---------------------------------------------------------------*/
  389.  
  390. void
  391. VirtualGDevice::Uninitialize()
  392. {
  393.     if (mDeviceBacking != NULL)
  394.     {
  395.         if (mAddedToDeviceList)
  396.         {
  397.             RecomputeGDHandle();
  398.             ::DMRemoveDisplay(mGDHandle, NULL);            
  399.             mAddedToDeviceList = false;
  400.         }
  401.  
  402.         if (mGDHandle != NULL)
  403.             ::DisposeGDevice(mGDHandle);
  404.         mGDHandle = NULL;
  405.  
  406.         ::DisposePtr(mDeviceBacking);
  407.         mDeviceBacking = NULL;
  408.     }
  409. }
  410.  
  411.  
  412. /*---------------------------------------------------------------
  413.     RecomputeGDHandle
  414. ---------------------------------------------------------------*/
  415.  
  416. void
  417. VirtualGDevice::RecomputeGDHandle()
  418. {
  419.     OSErr        err;
  420.  
  421.     err = ::DMGetGDeviceByDisplayID(mDisplayID, &mGDHandle, false);
  422.  
  423.     if (err != noErr)
  424.     {
  425.         DebugStr("\pFailedToFindDevice");
  426.         mGDHandle = NULL;
  427.     }
  428.     else
  429.     {
  430.         // Reset the backing address. It seems
  431.         // to get reset when we set the main device.
  432.         mGDHandle[0]->gdPMap[0]->baseAddr = mDeviceBacking;
  433.     }
  434. }
  435.  
  436.  
  437. /*---------------------------------------------------------------
  438.     LargeBlendEffect
  439. ---------------------------------------------------------------*/
  440.  
  441. LargeBlendEffect::LargeBlendEffect()
  442. {
  443.     mCircleData = ::Get1Resource('Circ', 128);
  444.     
  445.     if (mCircleData != NULL)
  446.         ::HLockHi(mCircleData);
  447.     
  448.     mMagnify = false;
  449. }
  450.  
  451.  
  452. /*---------------------------------------------------------------
  453.     BlendPixels
  454. ---------------------------------------------------------------*/
  455.  
  456. inline UInt16
  457. LargeBlendEffect::BlendPixels(
  458.     UInt16        inPixel1,
  459.     UInt16        inPixel2,
  460.     UInt32        inFraction)
  461. {
  462.     UInt32        red = ((inPixel1 >> 10) & 0x1f) * inFraction;
  463.     UInt32        green = ((inPixel1 >> 5) & 0x1f) * inFraction;
  464.     UInt32        blue = (inPixel1 & 0x1f) * inFraction;
  465.     UInt32        negFrac = 0x100 - inFraction;
  466.     
  467.     red += ((inPixel2 >> 10) & 0x1f) * negFrac;
  468.     green += ((inPixel2 >> 5) & 0x1f) * negFrac;
  469.     blue += (inPixel2 & 0x1f) * negFrac;
  470.     
  471.     return ((red >> 8) << 10) | ((green >> 8) << 5) | (blue >> 8);
  472. }
  473.  
  474.  
  475. /*---------------------------------------------------------------
  476.     AveragePixels
  477. ---------------------------------------------------------------*/
  478.  
  479. inline UInt16
  480. LargeBlendEffect::AveragePixels(
  481.     UInt16        inPixel1,
  482.     UInt16        inPixel2,
  483.     UInt16        inPixel3,
  484.     UInt16        inPixel4)
  485. {
  486.     UInt16        red = ((inPixel1 >> 10) & 0x1f) + ((inPixel2 >> 10) & 0x1f) + ((inPixel3 >> 10) & 0x1f) + ((inPixel4 >> 10) & 0x1f);
  487.     UInt16        green = ((inPixel1 >> 5) & 0x1f) + ((inPixel2 >> 5) & 0x1f) + ((inPixel3 >> 5) & 0x1f) + ((inPixel4 >> 5) & 0x1f);
  488.     UInt16        blue = (inPixel1 & 0x1f) + (inPixel2 & 0x1f) + (inPixel3 & 0x1f) + (inPixel4 & 0x1f);
  489.     
  490.     return ((red / 4) << 10) | ((green / 4) << 5) | (blue / 4);
  491. }
  492.  
  493.  
  494. /*---------------------------------------------------------------
  495.     RenderVirtualDevice
  496. ---------------------------------------------------------------*/
  497.  
  498. void
  499. LargeBlendEffect::RenderVirtualDevice(
  500.     const GraphicSurface &    inDestSurface,
  501.     VirtualGDevice *        inVDevice)
  502. {
  503.     // The panel blend effect simply involves
  504.     // copying some pixels from the first virtual
  505.     // device to the destination surface.
  506.     UInt32                 totalRows = inDestSurface.GetHeight();
  507.     UInt32                 totalCols = inDestSurface.GetWidth();
  508.     UInt8 *             srcPtr;
  509.     UInt8 *             destPtr;
  510.     UInt32                destRowBytes = inDestSurface.GetRowBytes();
  511.     UInt32                srcRowBytes = inVDevice->GetGraphicSurface().GetRowBytes();
  512.     Rect                circleRect;
  513.     UInt8 *                circleData = (UInt8 *)*mCircleData;
  514.     Point                mouseLoc;
  515.     double                dblBuffer;
  516.     UInt16 *            dblBuffer2 = (UInt16 *)&dblBuffer;
  517.     UInt32                bufferBytes = 0;
  518.     
  519.     mouseLoc = LMGetMouseLocation();
  520.     
  521.     circleRect.left = (mouseLoc.h - kCircleWidth) / 2;
  522.     circleRect.top = (mouseLoc.v - kCircleWidth) / 2;
  523.     circleRect.right = circleRect.left + kCircleWidth;
  524.     circleRect.bottom = circleRect.top + kCircleWidth;
  525.     
  526.     // Blit the first two screens
  527.     for (SInt32 row = 0; row < totalRows; row++)
  528.     {
  529.         destPtr = inDestSurface.GetPixelDataPtr() + destRowBytes * row;
  530.         srcPtr = inVDevice->GetGraphicSurface().GetPixelDataPtr() + srcRowBytes * row * 2;
  531.         
  532.         for (SInt32 col = 0; col < totalCols; col++)
  533.         {
  534.             UInt16        avePixel;
  535.             avePixel = AveragePixels(
  536.                     *(UInt16 *)srcPtr, 
  537.                     *(UInt16 *)(srcPtr + 2),
  538.                     *(UInt16 *)(srcPtr + srcRowBytes),
  539.                     *(UInt16 *)(srcPtr + srcRowBytes + 2));
  540.             
  541.             if (mMagnify &&
  542.                 row >= circleRect.top && 
  543.                 row < circleRect.bottom &&
  544.                 col >= circleRect.left &&
  545.                 col < circleRect.right)
  546.             {
  547.                 UInt32    blendAmount = circleData[(row - circleRect.top) * kCircleWidth + (col - circleRect.left)];
  548.  
  549.                 UInt8 * bigSrcPtr = inVDevice->GetGraphicSurface().GetPixelDataPtr();
  550.                 bigSrcPtr += (circleRect.top * 2 + row - circleRect.top + kCircleWidth / 2) * srcRowBytes;
  551.                 bigSrcPtr += (circleRect.left * 2 + col - circleRect.left + kCircleWidth / 2) * 2;
  552.                 UInt16    realPixValue = *(UInt16 *)bigSrcPtr;
  553.                 
  554.                 dblBuffer2[bufferBytes++] = BlendPixels(avePixel, realPixValue, blendAmount);
  555.             }
  556.             else
  557.             {
  558.                 dblBuffer2[bufferBytes++] = avePixel;
  559.             }
  560.  
  561.             if (bufferBytes >= 4)
  562.             {
  563.                 *(double *)destPtr = dblBuffer;
  564.                 bufferBytes = 0;
  565.                 destPtr += 8;
  566.             }
  567.             
  568.             srcPtr += 4;
  569.         }
  570.     }
  571. }
  572.  
  573.  
  574.  
  575.  
  576.  
  577.